/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.document.service.file.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.je.common.base.service.MetaService;
import com.je.common.base.util.StringUtil;
import com.je.document.entity.DocumentMetadataDO;
import com.je.document.entity.DocumentRelDO;
import com.je.document.reflection.BeanMappingHelper;
import com.je.document.service.file.FileMetaDataService;
import com.je.document.service.file.FileRelService;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.ibatis.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: jecloud-document
 * @author: LIULJ
 * @create: 2021-09-13 11:23
 * @description:
 */
@Service
public class FileRelServiceImpl implements FileRelService {

    @Autowired
    private MetaService metaService;
    @Autowired
    private FileMetaDataService fileMetaDataService;

    @Override
    public Map<String, Object> selectRelMapByKey(String key) {
        return selectRelMapByKey(key, null);
    }

    @Override
    public Map<String, Object> selectRelMapByKey(String key, String version) {
        //查询
        List<Map<String, Object>> list = new ArrayList<>();
        if (!Strings.isNullOrEmpty(version)) {
            list = selectListByKeysAndVersioin(Lists.newArrayList(key), version);
        } else {
            list = selectListByKeys(Lists.newArrayList(key));
        }
        if (list.size() > 0) {
            //文件信息
            Map<String, Object> map = list.get(0);
            //查询元数据
            List<DocumentMetadataDO> metadataDOS = fileMetaDataService.selectFileMetadata(key);
            //stream数据转换;  Map<relId, Map<元数据code, 元数据content>>
            Map<String, String> metadataMap = metadataDOS.stream()
                    //去重 relId+code
                    .collect(Collectors.collectingAndThen(
                            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(p -> p.getRelId() + p.getCode()))), ArrayList::new)).stream()
                    .collect(Collectors.toMap(p -> p.getCode(), p -> p.getContent()));
            //合并元数据，
            metadataMap.forEach((k, v) -> {
                //如果结果集中已有元数据code, 跳过
                if (map.containsKey(k)) {
                    return;
                }
                //元数据放入结果集
                map.put(k, v);
            });

            return map;
        }
        return null;
    }

    @Override
    public DocumentRelDO selectOneByKey(String key) {
        //查询
        Map<String, Object> map = selectRelMapByKey(key);
        if (map != null) {
            return BeanMappingHelper.transform(map, DocumentRelDO.class);
        }
        return null;
    }

    @Override
    public List<DocumentRelDO> selectRelByMetadata(JSONObject metadata) {
        List<Map<String, Object>> maps = selectFileMapByMetadata(metadata);
        return BeanMappingHelper.transformList(maps, DocumentRelDO.class);
    }

    @Override
    public List<Map<String, Object>> selectFileMapByMetadata(JSONObject metadata) {
        Page<Map<String, Object>> page = new Page(0, -1);
        Map<String, String> metadataMap = JSON.parseObject(metadata.toJSONString(), Map.class);
        List<Map<String, Object>> result = selectFileMapPageByMetadata(page, metadataMap, null);
        return result;
    }

    @Override
    public void deleteFilesByPkValues(String tableCode, String pkValues, String fieldCodes, String uploadTypes, String userId) {
        List<String> pkValueList = null;
        if (!Strings.isNullOrEmpty(pkValues)) {
            pkValueList = Splitter.on(",").splitToList(pkValues);
        }

        List<String> fieldCodeList = null;
        if (!Strings.isNullOrEmpty(fieldCodes)) {
            fieldCodeList = Splitter.on(",").splitToList(fieldCodes);
        }

        List<String> uploadTypeList = null;
        if (!Strings.isNullOrEmpty(uploadTypes)) {
            uploadTypeList = Splitter.on(",").splitToList(uploadTypes);
        }
        List<Map<String, Object>> relList = selectRelIdsByPkValues(tableCode, pkValueList, fieldCodeList, uploadTypeList);
        if (relList == null || relList.isEmpty()) {
            return;
        }
        List<String> relIdList = Lists.newArrayList();
        relList.forEach(eachMap -> {
            Object value = eachMap.get("id");
            if (value != null) {
                relIdList.add(value.toString());
            }
        });
        deleteFilesByRelId(relIdList, userId);
    }

    @Override
    public List<Map<String, Object>> selectListByKeys(List<String> keys) {
        StringBuffer sb = new StringBuffer();
        sb.append("select rel.*, ");
        sb.append("f.je_document_file_id AS fileId,rel.je_document_rel_id AS relId, rel.name AS relName, f.content_type AS contentType, f.bucket, f.thumbnail, ");
        sb.append("f.file_path AS filePath, f.file_size, rel.file_key AS fileKey, f.full_url AS fullUrl, f.suffix, rel.create_time AS createTime ");
        sb.append("from je_document_rel rel INNER JOIN je_document_file f on rel.file_id = f.je_document_file_id and f.is_deleted = 0 ");
        sb.append("where rel.is_deleted=0 and f.is_deleted=0 and file_key in ({0})");
        return metaService.selectSql(sb.toString(), keys);
    }

    @Override
    public List<Map<String, Object>> selectListByFileId(String fileId) {
        StringBuffer sb = new StringBuffer();
        sb.append("select file_id ");
        sb.append("from je_document_rel where is_deleted = 0 ");
        return metaService.selectSql(ConditionsWrapper.builder().apply(sb.toString()).eq("file_id",fileId));
    }

    @Override
    public List<Map<String, Object>> selectListByKeysAndVersioin(List<String> keys, String version) {
        StringBuffer sb = new StringBuffer();
        sb.append("select rel.*,");
        sb.append("f.je_document_file_id AS fileId,rel.je_document_rel_version_id AS relId, rel.name AS relName, f.content_type AS contentType, f.bucket, f.thumbnail, ");
        sb.append("f.file_path AS filePath, f.file_size, rel.file_key AS fileKey, f.full_url AS fullUrl, f.suffix, rel.create_time AS createTime ");
        sb.append("from je_document_rel_version rel INNER JOIN je_document_file f on rel.file_id = f.je_document_file_id and f.is_deleted = 0 ");
        sb.append("where rel.is_deleted=0 and f.is_deleted=0 and file_key in ({0}) and rel.version={1} ");
        return metaService.selectSql(sb.toString(), keys, version);
    }

    @Override
    public List<Map<String, Object>> selectFileMapPageByMetadata(Page<Map<String, Object>> page, Map<String, String> metadataMap, String orderBy) {

        return null;
    }

    @Override
    public List<Map<String, Object>> selectRelIdsByPkValues(String tableCode, List<String> pkValues, List<String> fieldCodes, List<String> uploadTypes) {
        StringBuffer sb = new StringBuffer();
        sb.append("select rel.je_document_rel_id from je_document_rel rel INNER JOIN je_document_metadata meta on meta.code = 'pkValue' ");
        sb.append("and meta.is_deleted =0 and rel.je_document_rel_id = meta.rel_id AND meta.content in ({0}) ");
        if (!Strings.isNullOrEmpty(tableCode)) {
            sb.append("inner join je_document_metadata meta1 on meta1.code = 'tableCode' AND meta1.content = '" + tableCode + "' AND ");
            sb.append("meta1.is_deleted =0 and rel.je_document_rel_id = meta1.rel_id ");
        }
        if (uploadTypes != null && !uploadTypes.isEmpty()) {
            sb.append("inner join je_document_metadata meta2 on meta2.code = 'uploadType' AND meta2.content in (" + StringUtil.buildArrayToString(uploadTypes) + ") AND meta2.is_deleted =0 and rel.je_document_rel_id = meta2.rel_id ");
        }
        if (fieldCodes != null && !fieldCodes.isEmpty()) {
            sb.append("inner join je_document_metadata meta3 on meta3.code = :code3 AND meta3.content in (" + StringUtil.buildArrayToString(fieldCodes) + ") AND meta3.is_deleted =0 and rel.je_document_rel_id = meta3.rel_id ");
        }
        return metaService.selectSql(sb.toString(), pkValues);
    }

    @Override
    public void deleteFilesByRelId(List<String> relIds, String userId) {
        metaService.executeSql("update je_document_rel SET is_deleted = 1,modified_time = NOW(), modified_user = {0} where is_deleted = 0 and je_document_rel_id in ({1})", userId, relIds);
    }

    @Override
    public void deleteFilesByKey(List<String> fileKeys, String userId) {
        if (fileKeys == null || fileKeys.isEmpty()) {
            return;
        }
        StringBuffer sb = new StringBuffer();
        sb.append("update je_document_rel ");
        sb.append("set is_deleted=1, modified_time=:time, modified_user={0} ");
        sb.append("where file_key in ({1}) ");
        metaService.executeSql(sb.toString(), userId, fileKeys);
    }

    @Override
    public void useFilesByKey(List<String> fileKeys, String userId) {
        if (fileKeys == null || fileKeys.isEmpty()) {
            return;
        }
        StringBuffer sb = new StringBuffer();
        sb.append("update je_document_rel ");
        sb.append("set is_deleted=0, modified_time=:time, modified_user={0} ");
        sb.append("where file_key in ({1}) ");
        metaService.executeSql(sb.toString(), userId, fileKeys);
    }

    @Override
    public void deleteFilesByFileRelIds(List<String> fileRelIds) {
        if (fileRelIds == null ||fileRelIds.isEmpty()){
            return;
        }
        StringBuffer sb = new StringBuffer();
        sb.append("delete from je_document_rel ");
        sb.append("where je_document_rel_id in ({0}) ");
        metaService.executeSql(sb.toString(), fileRelIds);
    }

    @Override
    public void deleteMetaDataByFileRelId(List<String> fileRelIds) {
        if (fileRelIds == null ||fileRelIds.isEmpty()){
            return;
        }
        StringBuffer sb = new StringBuffer();
        sb.append("delete from je_document_metadata ");
        sb.append("where rel_id in ({0}) ");
        metaService.executeSql(sb.toString(), fileRelIds);
    }

    @Override
    public void deleteFileByFileId(List<String> fileIds) {
        if (fileIds == null ||fileIds.isEmpty()){
            return;
        }
        StringBuffer sb = new StringBuffer();
        sb.append("delete from je_document_file ");
        sb.append("where je_document_file_id in ({0}) ");
        metaService.executeSql(sb.toString(), fileIds);
    }
    @Override
    public List<Map<String, Object>> selectMetaDataByFileKey(String fileKey) {
        if (fileKey == null ||fileKey.isEmpty()){
            return null;
        }
        StringBuffer sb = new StringBuffer();
        sb.append("select meta.code,rel.SY_CREATEORGNAME as department,rel.SY_CREATEUSERNAME as createUser,rel.file_key,rel.create_time as createTime,f.suffix,f.file_size as fileSize,rel.name ");
        sb.append("FROM JE_DOCUMENT_FILE f  JOIN je_document_rel rel on rel.file_id = f.je_document_file_id  JOIN je_document_metadata meta ON meta.rel_id = rel.je_document_rel_id");
        sb.append(" where code = 'createUserDept' AND file_key = '"+fileKey+"'");
        return metaService.selectSql(sb.toString());
    }

}
